/*!
*      \file Point2.h
*      \brief Two dimensional point class
*	   \author David Gu
*      \date 10/07/2010
*
*/

#include <math.h>
#include <assert.h>
#include <iostream>
#include <string>
#include <sstream>

#ifndef _T_MESHLIB_POINT2_H_
#define _T_MESHLIB_POINT2_H_




/*!
*	\brief CPoint2 class, two dimensional point
*
*	Two dimensional point \f$(x,y)\f$
*/
class CPoint2
{
	public:
	/*!
	*	CPoint2 default constructor, it is initialized to be (0,0)
	*/
    CPoint2(){ m_c[0] = 0; m_c[1] = 0; };
	/*!
	*	CPoint2 class copy operator
	*/
    CPoint2( const CPoint2 & uv ) {	m_c[0] = uv.m_c[0]; m_c[1] = uv.m_c[1];};
	/*!
	 *	CPoint2 class destructor
	 */
    ~CPoint2(){};
	
	 /*!
	  *	CPoint2 constructor with \f$(x,y)\f$
	  */
	 CPoint2( double  x, double y ) { m_c[0] = x; m_c[1] = y; };
	
	 /*!
	  *	reference to the values, CPoint2[0] x value ; CPoint2[1] y value; 
	  */
    double & operator[]( int i ) { 	assert( i < 2 && i >= 0 ); return m_c[i]; };

		bool operator==( const CPoint2 & uv ) 
		{
			return ( m_c[0] == uv.m_c[0] && m_c[1] == uv.m_c[1] );
		}

	 /*!
	  *	constant values, CPoint2[0] x value ; CPoint2[1] y value; 
	  */
    double  operator[]( int i ) const { 	assert( i < 2 && i >= 0 ); return m_c[i]; };

	/*! Divide by a scalor
	 *
	 */
    void operator/=( double s )
    {
      m_c[0]/=s;
      m_c[1]/=s;
    }

	/*! The norm of CPoint2 \f$\sqrt{x^2+y^2}\f$
	 *
	 */
	double norm() { return sqrt( m_c[0] * m_c[0] + m_c[1] * m_c[1] ); };

	/*! The square norm of CPoint2 \f$x^2+y^2\f$
	 *
	 */
	double norm2() { return  m_c[0] * m_c[0] + m_c[1] * m_c[1]; };

	/*!
	 * Add another point to the current point
	 * \param p
	 * \return cuccrent point is added by p.
	 */
	CPoint2  & operator += ( const CPoint2 & p) { m_c[0] += p[0]; m_c[1] += p[1]; return *this; }; 
	/*!
	 * Substract another point to the current point
	 * \param p
	 * \return cuccrent point is substracted by p.
	 */
	CPoint2  & operator -= ( const CPoint & p)  { m_c[0] -= p[0]; m_c[1] -= p[1]; return *this; };
	/*!
	 * Multiply by a scalar
	 * \param s scalar
	 * \return current point is multipolied by s.
	 */
	
	CPoint2  & operator *= ( const double  s) { m_c[0] *= s; m_c[1] *= s; return *this; };

	private:
		/*!
		* (x,y) value 
		*/
		double m_c[2];

};

/*!
*	summation of two two dimensional points
*   \param uv0 input two dimensional point
*   \param uv1 input two dimensional point
*   \return summation of uv0 and uv1
*/
inline CPoint2 operator+(  CPoint2 & uv0,  CPoint2 & uv1 )
{
	CPoint2 uv( uv0[0]+uv1[0], uv0[1] + uv1[1] );
	return uv;
};

/*!
*	difference between two two dimensional points
*   \param uv0 input two dimensional point
*   \param uv1 input two dimensional point
*   \return difference between uv0 and uv1
*/
inline CPoint2 operator-(  CPoint2 & uv0,  CPoint2 & uv1 )
{
	CPoint2 uv( uv0[0]-uv1[0], uv0[1] - uv1[1] );
	return uv;
};

/*!
*	multiply by a scalor
*   \param uv0 input two dimensional point
*   \param s  scalor
*   \return product of uv0 and s
*/
inline CPoint2 operator*(  CPoint2 & uv0, const double s )
{
	CPoint2 uv( uv0[0] * s, uv0[1] * s );
	return uv;
};

/*!
*	divide by a scalor
*   \param uv0 input two dimensional point
*   \param s  scalor
*   \return quotient between uv0 and s
*/

inline CPoint2 operator/(  CPoint2 & uv0, const double s )
{
	CPoint2 uv( uv0[0] / s, uv0[1] / s );
	return uv;
};

/*!
*	summation of two two dimensional points
*   \param uv0 input two dimensional point
*   \param uv1 input two dimensional point
*   \return summation of uv0 and uv1
*/
inline CPoint2 operator+(  const CPoint2 & uv0,  const CPoint2 & uv1 )
{
	CPoint2 uv( uv0[0]+uv1[0], uv0[1] + uv1[1] );
	return uv;
};

/*!
*	difference between two two dimensional points
*   \param uv0 input two dimensional point
*   \param uv1 input two dimensional point
*   \return difference between uv0 and uv1
*/
inline CPoint2 operator-(  const CPoint2 & uv0,  const CPoint2 & uv1 )
{
	CPoint2 uv( uv0[0]-uv1[0], uv0[1] - uv1[1] );
	return uv;
};

/*!
*	multiply by a scalor
*   \param uv0 input two dimensional point
*   \param s  scalor
*   \return product of uv0 and s
*/
inline CPoint2 operator*(  const CPoint2 & uv0, const double s )
{
	CPoint2 uv( uv0[0] * s, uv0[1] * s );
	return uv;
};

/*!
*	divide by a scalor
*   \param uv0 input two dimensional point
*   \param s  scalor
*   \return quotient between uv0 and s
*/
inline CPoint2 operator/(  const CPoint2 & uv0, const double s )
{
	CPoint2 uv( uv0[0] / s, uv0[1] / s );
	return uv;
};

/*!
 *	square of the norm of the CPoint2 \f$x^2+y^2\f$
 *  \param uv input two dimensional point
 *  \return square of the norm of the point
 */
inline double mag2(  CPoint2 & uv )
{
	return uv[0] * uv[0] + uv[1] * uv[1];
};

/*!
 *	norm of the CPoint2 \f$ \sqrt{x^2+y^2}\f$
 *  \param uv input two dimensional point
 *  \return norm of the point
 */
inline double mag(  CPoint2 & uv )
{
	return sqrt(uv[0] * uv[0] + uv[1] * uv[1]);
};

/*!
 *	cross product of two CPoint2
 *  \param uv1 the first  two diemenional point
 *  \param uv2 the second two diemenional point
 *  \return the cross product of the two points
 *  \f[
 *  \left|
 *	\begin{array}{cc}
 *  x_1 & y_1\\
 *  x_2 & y_2 \\
 *  \end{array}
 *	\right|
 *  \f]
 */

inline double cross(  CPoint2 uv1,  CPoint2 uv2 )
{
	return (uv1[0] * uv2[1] - uv1[1] * uv2[0]);
};


/*!
 *	inner product of two CPoint2
 *  \param a the first  two diemenional point
 *  \param b the second two diemenional point
 *  \return the inner product of the two points
 */
inline double operator*( CPoint2 a, CPoint2 b )
{
    return a[0] * b[0] + a[1] * b[1];
}

/*!
 *	cross product of two CPoint2
 *  \param uv1 the first  two diemenional point
 *  \param uv2 the second two diemenional point
 *  \return the cross product of the two points
 */

inline double operator^(  CPoint2 uv1,  CPoint2 uv2 )
{
	return (uv1[0] * uv2[1] - uv1[1] * uv2[0]);
};

/*!
 *	read in a CPoint2 from a string
 *  \param str input string
 *  \param c   the reference to a point
 *  \return the value of (x,y) read out from the string is assigned bo c
 */

inline void operator>>(const std::string & str, CPoint2& c )
{
	std::string t = str;
	t.erase(0, t.find_first_not_of("()") );
	t.erase(t.find_last_not_of("()") + 1);
	std::istringstream iss( t );

	iss >> c[0] >> c[1];
}



#endif
